﻿using System;
using UnityEngine;
using System.Collections.Generic;

namespace Miao
{


    /// <summary>
    /// 更新器
    /// 用于驱动所有方法
    /// </summary>
    public class Updater : MonoBehaviour
    {


        private readonly List<Action> updateFunctions = new List<Action>();
        private readonly List<Action> waitAddUpdateFunctions = new List<Action>();
        private readonly List<Action> waitRemoveUpdateFunctions = new List<Action>();

        private readonly List<DelayCallHandle> delayCallFunctions = new List<DelayCallHandle>();
        private readonly List<DelayCallHandle> waitAddDelayCallFunctions = new List<DelayCallHandle>();
        private readonly List<DelayCallHandle> waitRemoveDelayCallFunctions = new List<DelayCallHandle>();

        private readonly List<RepeatCallHandle> repeatCallFunctions = new List<RepeatCallHandle>();
        private readonly List<RepeatCallHandle> waitAddRepeatCallFunctions = new List<RepeatCallHandle>();
        private readonly List<RepeatCallHandle> waitRemoveRepeatCallFunctions = new List<RepeatCallHandle>();

        private readonly List<ConditionCallHandle> conditionCallFunctions = new List<ConditionCallHandle>();
        private readonly List<ConditionCallHandle> waitAddConditionCallFunctions = new List<ConditionCallHandle>();
        private readonly List<ConditionCallHandle> waitRemoveConditionCallFunctions = new List<ConditionCallHandle>();


        private void Update()
        {
            RemoveFunction();
            AddFunction();
            UpdateFunction();
        }

        private void OnDestroy()
        {
            MiaoRuntime.Updater = null;
        }
        /// <summary>
        /// 固定时间更新器
        /// </summary>
        /// <param name="updateFunction"></param>
        /// <param name="stepTime"></param>
        public RepeatCallHandle AddRepeatCall(Action repeatCall, float interval)
        {
            RepeatCallHandle repeatCallHandle = new RepeatCallHandle(repeatCall, interval);
            waitAddRepeatCallFunctions.Add(repeatCallHandle);
            return repeatCallHandle;
        }

        internal void RemoveRepeatCall(RepeatCallHandle function)
        {
            waitRemoveRepeatCallFunctions.Add(function);
        }
        /// <summary>
        /// 延迟呼叫
        /// </summary>
        /// <param name="delayCall"></param>
        /// <param name="delay"></param>
        /// <returns></returns>
        public DelayCallHandle AddDelayCall(Action delayCall, float delay)
        {
            DelayCallHandle delayCallHandle = new DelayCallHandle(delayCall, delay+Time.time);
            waitAddDelayCallFunctions.Add(delayCallHandle);
            return delayCallHandle;
        }
        internal void RemoveDelayCall(DelayCallHandle function)
        {
            waitRemoveDelayCallFunctions.Add(function);
        }

        public ConditionCallHandle AddConditionCall(Action repeatCall, Func<bool> condition)
        {
            ConditionCallHandle callHandle = new ConditionCallHandle(repeatCall, condition);
            waitAddConditionCallFunctions.Add(callHandle);
            return callHandle;
        }

        internal void RemoveConditionCall(ConditionCallHandle function)
        {
            waitRemoveConditionCallFunctions.Add(function);
        }

        /// <summary>
        /// 更新器
        /// </summary>
        /// <param name="updateFunction"></param>
        /// <returns></returns>
        public UpdateHandle AddUpdate(Action updateFunction)
        {
            UpdateHandle updateHandle = new UpdateHandle(updateFunction);
            waitAddUpdateFunctions.Add(updateFunction);
            return updateHandle;
        }
        internal void RemoveUpdate(Action updateFunction)
        {
            waitRemoveUpdateFunctions.Add(updateFunction);
        }



        private void AddFunction<T>(List<T> waitAddFunctionList, List<T> runningFunctionList) 
        {
            foreach (var waitAddFunction in waitAddFunctionList)
            {
              runningFunctionList.Add(waitAddFunction);
            }
            waitAddFunctionList.Clear();
        }
        private void RemoveFunction<T>(List<T> waitRemoveFunctionList, List<T> runningFunctionList)
        {
            foreach (var waitRemoveFunction in waitRemoveFunctionList)
            {
                runningFunctionList.Remove(waitRemoveFunction);
            }
            waitRemoveFunctionList.Clear();
        }
        private void UpdateFunction()
        {
            float time = Time.time;
            float deltaTime = Time.deltaTime;

            foreach (var Func in updateFunctions)
            {
                Func.Invoke();
            }
            foreach (var delayCall in delayCallFunctions)
            {
                if (delayCall.time < time)
                {
                    delayCall.delayCall.Invoke();
                    delayCall.Finish();
                }
            }
            foreach (var repeatCall in repeatCallFunctions)
            {
                repeatCall.timer += deltaTime;
                if (repeatCall.timer > repeatCall.interval)
                {
                    repeatCall.timer = 0;
                    repeatCall.repeatCall.Invoke();
                }
            }
            foreach (var conditionCall in conditionCallFunctions)
            {
               if(conditionCall.condition.Invoke())
               {
                  conditionCall.call.Invoke();
                  conditionCall.Finish();
               }
            }


        }
        private void AddFunction()
        {
            AddFunction(waitAddUpdateFunctions, updateFunctions);
            AddFunction(waitAddDelayCallFunctions, delayCallFunctions);
            AddFunction(waitAddRepeatCallFunctions, repeatCallFunctions);
            AddFunction(waitAddConditionCallFunctions, conditionCallFunctions);
        }
        internal void RemoveFunction()
        {
            RemoveFunction(waitRemoveUpdateFunctions, updateFunctions);
            RemoveFunction(waitRemoveDelayCallFunctions, delayCallFunctions);
            RemoveFunction(waitRemoveRepeatCallFunctions, repeatCallFunctions);
            RemoveFunction(waitRemoveConditionCallFunctions, conditionCallFunctions);
        }
    }
}